package bma.common.langutil.concurrent;

import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * 适合场景： 用于实现内容会快速失效的超时机制
 * 
 * @author 关中
 * @since 1.0
 * 
 */
public class RapidUpdateTimeline<ITEM> {

	protected static class Bulk<B_ITEM> {
		public long time;
		public List<B_ITEM> items;
	}

	private int tickDuration;
	private TreeMap<Long, Bulk<ITEM>> bulks = new TreeMap<Long, Bulk<ITEM>>();
	private Map<ITEM, Long> items;

	public RapidUpdateTimeline() {
		this(100, 128);
	}

	public RapidUpdateTimeline(int tickDuration, int mapsize) {
		if (tickDuration <= 0) {
			throw new IllegalArgumentException(
					"tickDuration must be greater than 0: " + tickDuration);
		}
		this.tickDuration = tickDuration;
		this.items = new HashMap<ITEM, Long>(mapsize);
	}

	public int getTickDuration() {
		return tickDuration;
	}

	public long bulkTime(long time) {
		return time / tickDuration;
	}

	public long nextTimeTick(long time) {
		long lastTickDelay = time % tickDuration;
		long r = time - lastTickDelay + tickDuration;
		return r==time?r+tickDuration:r;
	}
	public long timeTick(long time) {
		long lastTickDelay = time % tickDuration;
		return time - lastTickDelay;
	}

	public boolean add(long time, ITEM item) {
		long bt = bulkTime(time);
		synchronized (this) {
			if (items.containsKey(item)) {
				return false;
			}
			items.put(item, bt);
			Bulk<ITEM> bulk = bulks.get(bt);
			if (bulk == null) {
				bulk = new Bulk<ITEM>();
				bulk.time = bt;
				bulk.items = new LinkedList<ITEM>();
				bulks.put(bt, bulk);
			}
			bulk.items.add(item);
		}
		return true;
	}

	public boolean remove(ITEM item) {
		synchronized (this) {
			Long bt = items.remove(item);
			if (bt == null)
				return false;
			Bulk<ITEM> bulk = bulks.get(bt);
			if (bulk == null)
				return false;
			boolean r = bulk.items.remove(item);
			if (bulk.items.isEmpty()) {
				bulks.remove(bt);
			}
			return r;
		}
	}

	public boolean isEmpty() {
		synchronized (this) {
			return items.isEmpty();
		}
	}

	public static interface Processor<P_ITEM> {
		public void process(P_ITEM item);
	}

	public long processTickItems(long time, Processor<ITEM> p) {
		long bt = bulkTime(time);
		synchronized (this) {
			Iterator<Map.Entry<Long, Bulk<ITEM>>> it = bulks.entrySet()
					.iterator();
			while (it.hasNext()) {
				Map.Entry<Long, Bulk<ITEM>> e = it.next();
				if (e.getKey() > bt) {
					break;
				}

				Bulk<ITEM> bulk = e.getValue();
				for (ITEM item : bulk.items) {
					try {
						p.process(item);
					} catch (Exception err) {
					}
					items.remove(item);
				}
				bulk.items.clear();
				it.remove();
			}
		}
		return nextTimeTick(time);
	}

	public void clear(List<ITEM> remainItems) {
		synchronized (this) {
			if (remainItems != null) {
				remainItems.addAll(items.keySet());
			}
			items.clear();
			bulks.clear();
		}
	}

}
